﻿using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.IO;
using System.Windows;
using System.Windows.Markup;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Common;
using IssueVision.EntityModel;
using SL.IdentityModel.Services;

namespace IssueVision.ViewModel
{
    [Export(ViewModelTypes.MainPageViewModel, typeof(ViewModelBase))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class MainPageViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IAuthenticationModel _authenticationModel;
        private IPasswordResetModel _passwordResetModel;
        private IIssueVisionModel _issueVisionModel;
        #endregion "Private Data Members"

        #region "Constructor"
        [ImportingConstructor]
        public MainPageViewModel(IAuthenticationModel authModel, IPasswordResetModel passModel, IIssueVisionModel issueVisionModel)
        {
            _authenticationModel = authModel;
            _passwordResetModel = passModel;
            _issueVisionModel = issueVisionModel;

            // set up error handling
            _issueVisionModel.AllowMultipleErrors = false;
            _issueVisionModel.ClearLastError();

            // set up event handling
            _authenticationModel.SignInCompleted += _authenticationModel_SignInCompleted;
            _authenticationModel.SignOutCompleted += _authenticationModel_SignOutCompleted;
            _authenticationModel.PropertyChanged += _authenticationModel_PropertyChanged;
            _passwordResetModel.PropertyChanged += _passwordResetModel_PropertyChanged;
            _issueVisionModel.GetCurrentUserProfileResetCompleted += _issueVisionModel_GetCurrentUserProfileResetCompleted;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // set the initial values
            IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy || _issueVisionModel.IsBusy;
            IsLoggedIn = ClaimsIdentitySessionManager.Current.User.Identity.IsAuthenticated;
            IsLoggedOut = !(ClaimsIdentitySessionManager.Current.User.Identity.IsAuthenticated);
            IsAdmin = ClaimsIdentitySessionManager.Current.User.IsInRole(IssueVisionServiceConstant.UserTypeAdmin);
            if (ClaimsIdentitySessionManager.Current.User.Identity.IsAuthenticated)
                WelcomeText = "Welcome " + ClaimsIdentitySessionManager.Current.User.Identity.Name;
            else
                WelcomeText = string.Empty;
            // set the initial theme selection
            IsBureauBlueTheme = true;
            IsExpressionLightTheme = false;
            IsShinyBlueTheme = false;
            IsTwilightBlueTheme = false;
            // set the current active screen
            CurrentScreenText = ViewTypes.HomeView;
        }
        #endregion "Constructor"

        #region "Public Properties"

        private bool _isBusy;

        public bool IsBusy
        {
            get { return _isBusy; }
            private set
            {
                if (value != _isBusy)
                {
                    _isBusy = value;
                    RaisePropertyChanged("IsBusy");
                }
            }
        }

        private bool _isLoggedOut;

        public bool IsLoggedOut
        {
            get { return _isLoggedOut; }
            private set
            {
                if (value != _isLoggedOut)
                {
                    _isLoggedOut = value;
                    RaisePropertyChanged("IsLoggedOut");
                }
            }
        }

        private bool _isLoggedIn;

        public bool IsLoggedIn
        {
            get { return _isLoggedIn; }
            private set
            {
                if (value != _isLoggedIn)
                {
                    _isLoggedIn = value;
                    RaisePropertyChanged("IsLoggedIn");
                }
            }
        }

        private bool _isAdmin;

        public bool IsAdmin
        {
            get { return _isAdmin; }
            private set
            {
                if (value != _isAdmin)
                {
                    _isAdmin = value;
                    RaisePropertyChanged("IsAdmin");
                }
            }
        }

        private string _welcomeText;

        public string WelcomeText
        {
            get { return _welcomeText; }
            private set
            {
                if (value != _welcomeText)
                {
                    _welcomeText = value;
                    RaisePropertyChanged("WelcomeText");
                }
            }
        }

        private string _currentScreenText;

        public string CurrentScreenText
        {
            get { return _currentScreenText; }
            private set
            {
                if (value != _currentScreenText)
                {
                    _currentScreenText = value;
                    RaisePropertyChanged("CurrentScreenText");
                }
            }
        }


        private bool _isBureauBlueTheme;

        public bool IsBureauBlueTheme
        {
            get { return _isBureauBlueTheme; }
            private set
            {
                if (value != _isBureauBlueTheme)
                {
                    _isBureauBlueTheme = value;
                    RaisePropertyChanged("IsBureauBlueTheme");
                }
            }
        }

        private bool _isExpressionLightTheme;

        public bool IsExpressionLightTheme
        {
            get { return _isExpressionLightTheme; }
            private set
            {
                if (value != _isExpressionLightTheme)
                {
                    _isExpressionLightTheme = value;
                    RaisePropertyChanged("IsExpressionLightTheme");
                }
            }
        }

        private bool _isShinyBlueTheme;

        public bool IsShinyBlueTheme
        {
            get { return _isShinyBlueTheme; }
            private set
            {
                if (value != _isShinyBlueTheme)
                {
                    _isShinyBlueTheme = value;
                    RaisePropertyChanged("IsShinyBlueTheme");
                }
            }
        }

        private bool _isTwilightBlueTheme;

        public bool IsTwilightBlueTheme
        {
            get { return _isTwilightBlueTheme; }
            private set
            {
                if (value != _isTwilightBlueTheme)
                {
                    _isTwilightBlueTheme = value;
                    RaisePropertyChanged("IsTwilightBlueTheme");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand<Boolean> _logoutCommand;

        public RelayCommand<Boolean> LogoutCommand
        {
            get
            {
                if (_logoutCommand == null)
                {
                    _logoutCommand = new RelayCommand<Boolean>(
                        g => OnLogoutCommand(g));
                }
                return _logoutCommand;
            }
        }

        private void OnLogoutCommand(Boolean forceLogout)
        {
            try
            {
                if (!_authenticationModel.IsBusy)
                {
                    if (!_issueVisionModel.HasChanges)
                    {
                        // return back to the Home screen
                        AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                        CurrentScreenText = ViewTypes.HomeView;
                        // then logout
                        _authenticationModel.SignOutAsync();
                    }
                    else
                    {
                        // there are pending changes
                        MessageBoxResult theResult = MessageBoxResult.Cancel;

                        if (forceLogout)
                        {
                            // if forceLogout is true, no need to ask for confirmation
                            theResult = MessageBoxResult.OK;
                        }
                        else
                        {
                            // ask to confirm canceling any pending changes
                            DialogMessage dialogMessage = new DialogMessage(
                                this,
                                CommonResources.CancelAnyChangesMessageBoxText,
                                s => theResult = s)
                            {
                                Button = MessageBoxButton.OKCancel,
                                Caption = CommonResources.ConfirmMessageBoxCaption
                            };

                            AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                        }

                        if (theResult == MessageBoxResult.OK)
                        {
                            // if confirmed, cancel any pending changes
                            _issueVisionModel.RejectChanges();
                            // return back to the Home screen
                            AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                            CurrentScreenText = ViewTypes.HomeView;
                            // then logout
                            _authenticationModel.SignOutAsync();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand<string> _changeThemeCommand;

        public RelayCommand<string> ChangeThemeCommand
        {
            get
            {
                if (_changeThemeCommand == null)
                {
                    _changeThemeCommand = new RelayCommand<string>(
                        g => OnChangeThemeCommand(g),
                        g =>
                            {
                                var themeResource = Application.GetResourceStream(
                                    new Uri("/IssueVision.Client;component/Asset/" + g, UriKind.Relative));
                                return themeResource != null;
                            });
                }
                return _changeThemeCommand;
            }
        }

        private void OnChangeThemeCommand(String g)
        {
            try
            {
                if (g == "BureauBlue.xaml" || g == "ExpressionLight.xaml" ||
                    g == "ShinyBlue.xaml" || g == "TwilightBlue.xaml")
                {
                    // remove the old one
                    Application.Current.Resources.MergedDictionaries.RemoveAt(Application.Current.Resources.MergedDictionaries.Count - 1);
                    // find and add the new one
                    var themeResource = Application.GetResourceStream(new Uri("/IssueVision.Client;component/Asset/" + g, UriKind.Relative));
                    ResourceDictionary rd = (ResourceDictionary)(XamlReader.Load(new StreamReader(themeResource.Stream).ReadToEnd()));
                    Application.Current.Resources.MergedDictionaries.Add(rd);

                    // notify the change
                    if (g == "BureauBlue.xaml")
                    {
                        IsBureauBlueTheme = true;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "ExpressionLight.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = true;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "ShinyBlue.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = true;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "TwilightBlue.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = true;
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand<string> _changeScreenCommand;

        public RelayCommand<string> ChangeScreenCommand
        {
            get
            {
                if (_changeScreenCommand == null)
                {
                    _changeScreenCommand = new RelayCommand<string>(
                        g => OnChangeScreenCommand(g),
                        g => g != null);
                }
                return _changeScreenCommand;
            }
        }

        private void OnChangeScreenCommand(String g)
        {
            try
            {
                if (CurrentScreenText != g)
                {
                    if (!_issueVisionModel.HasChanges)
                    {
                        // if no pending changes, switch to the new screen
                        switch (g)
                        {
                            case ViewTypes.HomeView:
                                // return back to the Home screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                                CurrentScreenText = ViewTypes.HomeView;
                                break;
                            case ViewTypes.NewIssueView:
                                // open the NewIssue screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.NewIssueView);
                                CurrentScreenText = ViewTypes.NewIssueView;
                                break;
                            case ViewTypes.AllIssuesView:
                                // open the AllIssues screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.AllIssuesView);
                                CurrentScreenText = ViewTypes.AllIssuesView;
                                break;
                            case ViewTypes.MyIssuesView:
                                // open the MyIssues screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.MyIssuesView);
                                CurrentScreenText = ViewTypes.MyIssuesView;
                                break;
                            case ViewTypes.BugReportView:
                                // open the BugReport screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.BugReportView);
                                CurrentScreenText = ViewTypes.BugReportView;
                                break;
                            case ViewTypes.MyProfileView:
                                // open the MyProfile screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.MyProfileView);
                                CurrentScreenText = ViewTypes.MyProfileView;
                                break;
                            case ViewTypes.UserMaintenanceView:
                                // open the UserMaintenance screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.UserMaintenanceView);
                                CurrentScreenText = ViewTypes.UserMaintenanceView;
                                break;
                            case ViewTypes.AuditIssueView:
                                // open the AuditIssue screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.AuditIssueView);
                                CurrentScreenText = ViewTypes.AuditIssueView;
                                break;
                            default:
                                throw new NotImplementedException();
                        }
                    }
                    else
                    {
                        // there are pending changes
                        MessageBoxResult theResult = MessageBoxResult.Cancel;

                        // ask to confirm canceling any pending changes
                        DialogMessage dialogMessage = new DialogMessage(
                            this,
                            CommonResources.CancelAnyChangesMessageBoxText,
                            s => theResult = s)
                        {
                            Button = MessageBoxButton.OKCancel,
                            Caption = CommonResources.ConfirmMessageBoxCaption
                        };

                        AppMessages.PleaseConfirmMessage.Send(dialogMessage);

                        if (theResult == MessageBoxResult.OK)
                        {
                            // if confirmed, cancel any pending changes
                            _issueVisionModel.RejectChanges();
                            // and switch to the new screen
                            switch (g)
                            {
                                case ViewTypes.HomeView:
                                    // return back to the Home screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                                    CurrentScreenText = ViewTypes.HomeView;
                                    break;
                                case ViewTypes.NewIssueView:
                                    // open the NewIssue screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.NewIssueView);
                                    CurrentScreenText = ViewTypes.NewIssueView;
                                    break;
                                case ViewTypes.AllIssuesView:
                                    // open the AllIssues screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.AllIssuesView);
                                    CurrentScreenText = ViewTypes.AllIssuesView;
                                    break;
                                case ViewTypes.MyIssuesView:
                                    // open the MyIssues screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.MyIssuesView);
                                    CurrentScreenText = ViewTypes.MyIssuesView;
                                    break;
                                case ViewTypes.BugReportView:
                                    // open the BugReport screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.BugReportView);
                                    CurrentScreenText = ViewTypes.BugReportView;
                                    break;
                                case ViewTypes.MyProfileView:
                                    // open the MyProfile screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.MyProfileView);
                                    CurrentScreenText = ViewTypes.MyProfileView;
                                    break;
                                case ViewTypes.UserMaintenanceView:
                                    // open the UserMaintenance screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.UserMaintenanceView);
                                    CurrentScreenText = ViewTypes.UserMaintenanceView;
                                    break;
                                case ViewTypes.AuditIssueView:
                                    // open the AuditIssue screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.AuditIssueView);
                                    CurrentScreenText = ViewTypes.AuditIssueView;
                                    break;
                                default:
                                    throw new NotImplementedException();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        /// <summary>
        /// Event handler for SignInCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _authenticationModel_SignInCompleted(object sender, SignInEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.User != null)
                {
                    IsLoggedIn = e.User.Identity.IsAuthenticated;
                    IsLoggedOut = !(e.User.Identity.IsAuthenticated);
                    IsAdmin = e.User.IsInRole(IssueVisionServiceConstant.UserTypeAdmin);

                    if (e.User.Identity.IsAuthenticated)
                    {
                        WelcomeText = "Welcome " + e.User.Identity.Name;
                        // check whether the user needs to reset profile
                        _issueVisionModel.GetCurrentUserProfileResetAsync();
                    }
                }
            }
        }

        /// <summary>
        /// Event handler for SignOutCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _authenticationModel_SignOutCompleted(object sender, SignOutEventArgs e)
        {
            // even if e.HasError is True, we still set logout done.
            IsLoggedIn = false;
            IsLoggedOut = true;
            IsAdmin = false;
            WelcomeText = string.Empty;
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _authenticationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy || _issueVisionModel.IsBusy;
                    break;
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _passwordResetModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy || _issueVisionModel.IsBusy;
                    break;
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy || _issueVisionModel.IsBusy;
                    break;
            }
        }

        /// <summary>
        /// Event handler for GetCurrentUserProfileResetCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetCurrentUserProfileResetCompleted(object sender, ResultArgs<bool> e)
        {
            if (!e.HasError)
            {
                if (e.Results)
                {
                    // open the MyProfile screen
                    AppMessages.ChangeScreenMessage.Send(ViewTypes.MyProfileView);
                    CurrentScreenText = ViewTypes.MyProfileView;
                }
                else
                {
                    // otherwise, open the home screen
                    AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                    CurrentScreenText = ViewTypes.HomeView;
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        #endregion "Private Methods"
    }
}
